#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 跨平台信号处理所需头文件
#ifdef _WIN32
#include <windows.h>
#else
#include <signal.h>
#include <unistd.h>
#endif

#define MINISQL_IMPLEMENTATION
#include "minisql.hol.h"

// 全局数据库指针，用于信号处理函数访问
static MiniSQL* g_db = NULL;

// 信号处理函数：确保退出前保存数据
#ifdef _WIN32
BOOL WINAPI ConsoleHandler(DWORD dwCtrlType) {
    if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
        if (g_db) {
            printf("\n捕获到中断，正在保存数据...\n");
            minisql_close(g_db);  // 关闭数据库，确保数据写入磁盘
        }
        printf("程序已安全退出\n");
        exit(0);
        return TRUE;
    }
    return FALSE;
}
#else
static void signal_handler(int sig) {
    if (sig == SIGINT) {  // 捕获Ctrl+C信号
        if (g_db) {
            printf("\n捕获到中断，正在保存数据...\n");
            minisql_close(g_db);  // 关闭数据库，确保数据写入磁盘
        }
        printf("程序已安全退出\n");
        exit(0);
    }
}
#endif

// 初始化Todo表
void init_todo_table(MiniSQL* db) {
    const char* create_sql = "CREATE TABLE todo ("
                            "id INT PRIMARY KEY,"
                            "task TEXT,"
                            "status INT)"; // 0=未完成, 1=已完成
    ResultSet* result = NULL;
    minisql_exec(db, create_sql, &result);
    if (result) minisql_free_result(result);
}

// 添加任务（处理单引号转义）
void add_task(MiniSQL* db, int id, const char* task) {
    char sql[1024];
    // 转义单引号（避免SQL格式错误）
    char escaped_task[1024];
    strcpy(escaped_task, task);
    char* p = strchr(escaped_task, '\'');
    while (p) {
        memmove(p+1, p, strlen(p)+1);
        *p = '\''; // 双写单引号转义
        p = strchr(p+2, '\'');
    }
    snprintf(sql, sizeof(sql), 
             "INSERT INTO todo VALUES (%d, '%s', 0)", id, escaped_task);
    ResultSet* result = NULL;
    int rc = minisql_exec(db, sql, &result);
    if (rc != MINISQL_OK) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "添加失败: %s\n" , minisql_errmsg(db));
        #else
        printf("添加失败: %s\n", minisql_errmsg(db));
        #endif
    } else {
        #ifdef HAS_COLOR_PRINT
        cprintf( "添加成功（id=%d）\n" , id);
        #else
        printf("添加成功（id=%d）\n", id);
        #endif
    }
    if (result) minisql_free_result(result);
}

// 查看任务列表
void list_tasks(MiniSQL* db) {
    const char* sql = "SELECT id, task, status FROM todo;";
    ResultSet* result = NULL;
    int rc = minisql_exec(db, sql, &result);
    if (rc != MINISQL_OK) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "查询失败: %s\n" , minisql_errmsg(db));
        #else
        printf("查询失败: %s\n", minisql_errmsg(db));
        #endif
        return;
    }

    if (!result || result->row_count == 0) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "暂无任务\n" );
        #else
        printf("暂无任务\n");
        #endif
        minisql_free_result(result);
        return;
    }

    // 打印MD格式任务列表
    #ifdef HAS_COLOR_PRINT
    cprintf( "| id | 任务                 | 状态   |\n");
    cprintf("|----|----------------------|--------|\n" );
    #else
    printf("| id | 任务                 | 状态   |\n");
    printf("|----|----------------------|--------|\n");
    #endif
    for (int i = 0; i < result->row_count; i++) {
        Row* row = result->rows[i];
        int id = row->values[0].as.i;
        const char* task = row->values[1].as.s;
        const char* status = (row->values[2].as.i == 0) ? 
            "未完成" : "已完成";
        printf("| %-2d | %-20s | %-6s |\n", id, task, status);
    }
    minisql_free_result(result);
}

// 标记任务为完成
void complete_task(MiniSQL* db, int id) {
    char sql[1024];
    snprintf(sql, sizeof(sql), 
             "UPDATE todo SET status=1 WHERE id=%d;", id);
    ResultSet* result = NULL;
    int rc = minisql_exec(db, sql, &result);
    if (rc != MINISQL_OK) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "更新失败: %s\n" , minisql_errmsg(db));
        #else
        printf("更新失败: %s\n", minisql_errmsg(db));
        #endif
    } else {
        #ifdef HAS_COLOR_PRINT
        cprintf( "已标记任务（id=%d）为完成\n" , id);
        #else
        printf("已标记任务（id=%d）为完成\n", id);
        #endif
    }
    if (result) minisql_free_result(result);
}

// 删除任务
void delete_task(MiniSQL* db, int id) {
    char sql[1024];
    snprintf(sql, sizeof(sql), 
             "DELETE FROM todo WHERE id=%d;", id);
    ResultSet* result = NULL;
    int rc = minisql_exec(db, sql, &result);
    if (rc != MINISQL_OK) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "删除失败: %s\n" , minisql_errmsg(db));
        #else
        printf("删除失败: %s\n", minisql_errmsg(db));
        #endif
    } else {
        #ifdef HAS_COLOR_PRINT
        cprintf( "已删除任务（id=%d）\n" , id);
        #else
        printf("已删除任务（id=%d）\n", id);
        #endif
    }
    if (result) minisql_free_result(result);
}

// 帮助信息（MD格式）
void print_help() {
    #ifdef HAS_COLOR_PRINT
    cprintf( "\n### Todo 程序使用帮助 ###\n\n" );
    #else
    printf("\n### Todo 程序使用帮助 ###\n\n");
    #endif
    printf("| 命令 | 格式 | 示例 |\n");
    printf("|------|------|------|\n");
    printf("| 添加任务 | add <id> <任务内容> | add 1 买牛奶 |\n");
    printf("| 查看任务 | list | list |\n");
    printf("| 标记完成 | complete <id> | complete 1 |\n");
    printf("| 删除任务 | delete <id> | delete 1 |\n");
    printf("| 退出 | exit | exit |\n");
}

int main() {
    // 初始化数据库并赋值给全局指针
    g_db = minisql_open("todo_db");
    if (!g_db) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "无法打开数据库\n" );
        #else
        printf("无法打开数据库\n");
        #endif
        return 1;
    }

    // 注册跨平台中断处理函数
#ifdef _WIN32
    if (!SetConsoleCtrlHandler(ConsoleHandler, TRUE)) {
        printf("警告: 无法设置控制台中断处理，Ctrl+C可能导致数据丢失\n");
    }
#else
    signal(SIGINT, signal_handler);  // 捕获Ctrl+C信号
#endif

    init_todo_table(g_db);

    #ifdef HAS_COLOR_PRINT
    cprintf( "Todo 程序（输入 'help' 查看命令）\n" );
    #else
    printf("Todo 程序（输入 'help' 查看命令）\n");
    #endif
    char* line = NULL;
    size_t len = 0;

    while (1) {
        #ifdef HAS_COLOR_PRINT
        cprintf( "todo> " );
        #else
        printf("todo> ");
        #endif
        ssize_t read = getline(&line, &len, stdin);
        if (read == -1) break;

        // 处理输入
        if (read > 0 && line[read-1] == '\n') line[read-1] = '\0';
        char* cmd = line;
        while (*cmd && isspace((unsigned char)*cmd)) cmd++;
        if (*cmd == '\0') continue;

        char* token = strtok(cmd, " ");
        if (!token) continue;

        if (strcmp(token, "exit") == 0) break;
        else if (strcmp(token, "help") == 0) print_help();
        else if (strcmp(token, "add") == 0) {
            char* id_str = strtok(NULL, " ");
            char* task = strtok(NULL, "");
            if (!id_str || !task) {
                #ifdef HAS_COLOR_PRINT
                cprintf( "用法: add <id> <任务内容>\n" );
                #else
                printf("用法: add <id> <任务内容>\n");
                #endif
                continue;
            }
            add_task(g_db, atoi(id_str), task);
        } else if (strcmp(token, "list") == 0) list_tasks(g_db);
        else if (strcmp(token, "complete") == 0) {
            char* id_str = strtok(NULL, " ");
            if (!id_str) {
                #ifdef HAS_COLOR_PRINT
                cprintf( "用法: complete <id>\n" );
                #else
                printf("用法: complete <id>\n");
                #endif
                continue;
            }
            complete_task(g_db, atoi(id_str));
        } else if (strcmp(token, "delete") == 0) {
            char* id_str = strtok(NULL, " ");
            if (!id_str) {
                #ifdef HAS_COLOR_PRINT
                cprintf("用法: delete <id>\n");
                #else
                printf("用法: delete <id>\n");
                #endif
                continue;
            }
            delete_task(g_db, atoi(id_str));
        } else {
            #ifdef HAS_COLOR_PRINT
            cprintf("未知命令！输入 'help' 查看帮助\n");
            #else
            printf("未知命令！输入 'help' 查看帮助\n");
            #endif
        }
    }

    // 正常退出时关闭数据库
    free(line);
    minisql_close(g_db);
    g_db = NULL;  // 避免信号处理函数重复关闭
    #ifdef HAS_COLOR_PRINT
    cprintf( "程序退出\n" );
    #else
    printf("程序退出\n");
    #endif
    return 0;
}